package com.yonyou.pmclouds.plan.controller;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import com.alibaba.dubbo.config.annotation.Reference;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.basecom.util.DateUtils;
import com.yonyou.pmclouds.billtype.util.BillTypeInfoQueryUtils;
import com.yonyou.pmclouds.billtype.util.DepartmentInfoQueryUtils;
import com.yonyou.pmclouds.milestone.entity.MilestoneVO;
import com.yonyou.pmclouds.milestone.service.IMilestoneQuery;
import com.yonyou.pmclouds.outter.user.UserInfoQuery;
import com.yonyou.pmclouds.plan.entity.*;
import com.yonyou.pmclouds.plan.plandriven.entity.NcDepartmentVO;
import com.yonyou.pmclouds.plan.plandriven.entity.NcDeptQueryParamVO;
import com.yonyou.pmclouds.plan.rmiitf.IPlanVersionWebService;
import com.yonyou.pmclouds.plan.rmiitf.IScheduleQueryService;
import com.yonyou.pmclouds.plan.rmiitf.IScheduleService;
import com.yonyou.pmclouds.team.entity.TeamMemberVO;
import com.yonyou.pmclouds.team.rmiitf.TeamMemberQuery;
import com.yonyou.pmclouds.user.entity.UserInfo;
import com.yonyou.pmclouds.workflow.aspect.PMApprove;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @Description: 进度计划编制WEB端
 * @Author: zhangzhonghao
 * @Date: 2020-03-06
 */

@Slf4j
@RestController
@RequestMapping("/schedule")
public class ScheduleWebController {

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private IScheduleService scheduleService;

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private IScheduleQueryService scheduleQueryService;

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private IMilestoneQuery milestoneQuery;

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private TeamMemberQuery teamMemberQuery;

    @Autowired
    private BillTypeInfoQueryUtils billTypeInfoQueryUtils;

    @Autowired
    private DepartmentInfoQueryUtils departmentInfoQueryUtils;

    @Autowired
    private UserInfoQuery userInfoQuery;

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private IPlanVersionWebService iPlanVersionWebService;


    /**
     * 对选定版本号和上个版本号的业务数据进行内容对比
     * @param pkSchedule  当前版本号主键
     * @param version  当前版本号
     * @return
     * @throws BusinessException
     */
    @GetMapping("/compare")
    public ScheduleVO compare(@RequestParam("pkSchedule") String pkSchedule,@RequestParam("version") Integer version) throws BusinessException {
        String preScheduleId = scheduleQueryService.findByPreId(pkSchedule, version);

        if(preScheduleId.equals(StringUtils.EMPTY)){
            throw new BusinessException("没有找到上个版本的信息");
        }

        List<ScheduleVO> scheduleVOS = scheduleQueryService.queryByIds(new String[]{pkSchedule, preScheduleId});

        setRelatedValue(scheduleVOS.toArray(new ScheduleVO[]{}));

        return iPlanVersionWebService.compare(scheduleVOS,pkSchedule,preScheduleId);
    }

    /**
     * 计划名称点击联动
     * @param pkOriginal
     * @return
     * @throws BusinessException
     */
    @GetMapping("/history")
    public ScheduleVO[] history(@RequestParam("pkOriginal") String pkOriginal) throws BusinessException {
        ScheduleVO[] allVersions = scheduleQueryService.queryByPkOriginal(pkOriginal);

        if(ArrayUtils.isEmpty(allVersions)){
            return new ScheduleVO[0];
        }else{
            setRelatedValue(allVersions);
            return allVersions;
        }
    }

    /**
     * 计划编制保存接口
     *
     * @param scheduleVO 计划编制VO
     * @return 计划VO
     */
    @RequestMapping("/save")
    public ScheduleVO insert(@RequestBody ScheduleVO scheduleVO) throws BusinessException {
        return scheduleService.insert(scheduleVO);
    }

    /**
     * 计划编制删除接口
     *
     * @param scheduleVO 计划编制VO
     * @return 计划VO
     */
    @RequestMapping("/delete")
    public ScheduleVO delete(@RequestBody ScheduleVO scheduleVO) throws BusinessException {
        return scheduleService.delete(scheduleVO);
    }

    /**
     * 计划编制查询项目下的所有生效的计划，包含计划任务详情
     *
     * @param pkProject 项目主键
     * @return 计划VO数组
     */
    @RequestMapping("/queryByPkProject")
    public List<ScheduleVO> queryByPkProject(@RequestParam("pkProject") String pkProject) throws BusinessException {
        List<ScheduleVO> scheduleVOS = scheduleQueryService.queryByPkProject(pkProject);

        if (scheduleVOS == null || scheduleVOS.size() <= 0) {
            return new ArrayList<>();
        }

        setRelatedValue(scheduleVOS.toArray(new ScheduleVO[]{}));

        return scheduleVOS;
    }

    @RequestMapping("/queryByProjectId")
    public List<ScheduleVO> queryByProjectId(@RequestParam("pkProject") String pkProject) throws BusinessException {
        return scheduleQueryService.queryByProjectId(pkProject);
    }

    /**
     * 通过计划编制主键查询计划详情接口，包含子表与关联项的值
     *
     * @param pkSchedule 计划编制主键
     * @return 计划VO
     */
    @RequestMapping("/queryById")
    public ScheduleVO queryByPk(@RequestParam("pkSchedule") String pkSchedule) throws BusinessException {
        ScheduleVO scheduleVO = scheduleQueryService.queryById(pkSchedule);
        if (scheduleVO == null) {
            return null;
        }

        setRelatedValue(new ScheduleVO[]{scheduleVO});

        return scheduleVO;
    }

    /**
     * 计划编制审批流提交接口
     *
     * @param scheduleVO 计划VO
     * @return 计划VO
     */
    @PMApprove(trigger = "commit")
    @RequestMapping("/commit")
    public ScheduleVO commit(@RequestBody ScheduleVO scheduleVO) throws BusinessException {
        return scheduleService.commit(scheduleVO);
    }

    /**
     * 计划调整接口
     *
     * @param scheduleVO 调整后数据
     * @return 保存后结果
     */
    @RequestMapping("/adjust")
    public ScheduleVO adjust(@RequestBody ScheduleVO scheduleVO) throws BusinessException {
        return scheduleService.updateScheduleForAdjust(scheduleVO);
    }

    /**
     * 统计分析计划看板接口
     *
     * @param tenantId   租户ID
     * @param filterCode 页签过滤编码：ongoing（进行中）、completed（已完成）、all（全部）
     * @param sortField  排序字段，多个字段用逗号拼接
     * @param sortWay    排序方式，与排序字段对应，多个用逗号拼接
     * @return 项目VO
     */
    @GetMapping("/tenantId")
    public List<ProjectScheduleBoardVO> queryByTenantId(@RequestParam("tenantId") String tenantId, @RequestParam("filterCode") String filterCode,
                                                        @RequestParam("sortField") String sortField, @RequestParam("sortWay") String sortWay,
                                                        @RequestParam("orgId") String orgId) throws BusinessException {

        List<ProjectScheduleBoardVO> scheduleBoardVOS = scheduleQueryService.queryProjectScheduleBoard(tenantId,
                filterCode, sortField, sortWay, orgId);

        userInfoQuery.tranUserInfoField(scheduleBoardVOS.toArray(new ProjectScheduleBoardVO[]{}),
                new String[]{ProjectScheduleBoardVO.MANAGER}, new String[]{ProjectScheduleBoardVO.MANAGER_NAME});

        return scheduleBoardVOS;
    }

    /**
     * 计划编制、计划模板，查询nc部门
     * @param pkOrg 组织主键
     * @param pkProject 项目主键
     * @return 部门信息
     */
    @RequestMapping("/queryDept")
    public List<NcDepartmentVO> queryDepartment(@RequestParam(value = "pkOrg", required = false) String pkOrg,
                                                @RequestParam(value = "pkProject", required = false) String pkProject) throws BusinessException {
        if (StringUtils.isEmpty(pkOrg) && StringUtils.isEmpty(pkProject))
            return new ArrayList<>();

        return departmentInfoQueryUtils.queryDepartment(new NcDeptQueryParamVO(pkOrg, pkProject, null));
    }

    @RequestMapping("/importFromExcel")
    public ScheduleItemVO[] importFromExcel(@RequestParam(value="file") MultipartFile file, @RequestBody ScheduleVO scheduleVO) throws BusinessException {
        checkImportFromExcel(file, scheduleVO);

        //解析Excel
        List<ProjectPlanImportVO> planList = analyzeExcel(file);
        if(planList == null || planList.size() <= 0){
            return new ScheduleItemVO[0];
        }

        // 翻译关联项的值
        setExcelRelateValue(planList);

        // 转换为任务项VO
        setImportItems(planList, scheduleVO);

        return scheduleVO.getScheduleItemVOS();
    }

    private void setImportItems(List<ProjectPlanImportVO> planList, ScheduleVO scheduleVO){
        List<ScheduleItemVO> itemVOS = new ArrayList<>();
        for(ProjectPlanImportVO importVO : planList){
            ScheduleItemVO itemVO = new ScheduleItemVO();
            itemVO.setCode(importVO.getScode());
            itemVO.setName(importVO.getSname());
            itemVO.setPlanDays(importVO.getExpeDuration());
            itemVO.setPkMilestone(importVO.getPkMilestone());
            itemVO.setMilestoneName(importVO.getMilestoneName());
            itemVO.setMilestoneCode(importVO.getMilestoneCode());
            itemVO.setDependPlanName(importVO.getDependPlanName());
            itemVO.setPlanStartDate(importVO.getExpeStartDate());
            itemVO.setPlanEndDate(importVO.getExpeEndDate());

            itemVOS.add(itemVO);
        }

        // 构造树结构，并返回根节点信息
        List<ScheduleItemVO> rootItemList = this.getItemOnlyRoot(itemVOS);

        // 如果存在手动创建的任务项，则导入的放在已创建之后，编码重排
        setNewCode(scheduleVO, rootItemList);

        if(rootItemList.size() > 0){
            scheduleVO.setScheduleItemVOS(rootItemList.toArray(new ScheduleItemVO[]{}));
        }
    }

    /**
     * 如果存在手动创建的任务项，则导入的放在已创建之后，编码重排
     * @param scheduleVO 前端已编制VO
     * @param rootItemList 模版导入的VO
     */
    private void setNewCode(ScheduleVO scheduleVO, List<ScheduleItemVO> rootItemList ){
        int childCount = scheduleVO.getChildCount();
        if(childCount <= 0){
            return;
        }

        Map<String, String> newWithOldCodeMap = new HashMap<>();
        for(ScheduleItemVO itemVO : rootItemList){
            String code = itemVO.getCode();
            String newCode = String.valueOf(Integer.parseInt(code) + childCount);
            newWithOldCodeMap.put(code, newCode);
            itemVO.setCode(newCode);
            itemVO.setSeq(Integer.parseInt(newCode));
            setChildNewCode(newWithOldCodeMap, itemVO);
        }

        setNewDependCode(newWithOldCodeMap, rootItemList);
    }

    private void setNewDependCode(Map<String, String> newWithOldCodeMap, List<ScheduleItemVO> rootItemList){
        for(ScheduleItemVO itemVO : rootItemList){
            setChildNewDependCode(newWithOldCodeMap, itemVO);
        }
    }

    private void setChildNewDependCode(Map<String, String> newWithOldCodeMap, ScheduleItemVO parentItemVO){
        if(StringUtils.isNotEmpty(parentItemVO.getDependPlanName())){
            parentItemVO.setDependPlanName(newWithOldCodeMap.get(parentItemVO.getDependPlanName()));
        }

        if(parentItemVO.getChildren() == null || parentItemVO.getChildren().length <= 0){
            return;
        }

        for(ScheduleItemVO childItemVO : parentItemVO.getChildren()){
            setChildNewDependCode(newWithOldCodeMap, childItemVO);
        }
    }

    private void setChildNewCode(Map<String, String> newWithOldCodeMap, ScheduleItemVO parentItemVO){
        if(parentItemVO.getChildren() == null || parentItemVO.getChildren().length <= 0){
            return;
        }

        String parentCode = parentItemVO.getCode();
        ScheduleItemVO[] childItems = parentItemVO.getChildren();
        for(ScheduleItemVO childItemVO : childItems){
            String childCode = childItemVO.getCode();
            String newChildCode = parentCode + childCode.substring(parentCode.length());
            newWithOldCodeMap.put(childCode, newChildCode);
            childItemVO.setCode(newChildCode);
            setChildNewCode(newWithOldCodeMap, childItemVO);
        }

    }

    private List<ScheduleItemVO> getItemOnlyRoot(List<ScheduleItemVO> itemVOS){
        this.genItemTree(itemVOS);
        List<ScheduleItemVO> rootItemList = new ArrayList<>();
        for(ScheduleItemVO itemVO : itemVOS){
            if(!itemVO.getCode().contains(".")){
                rootItemList.add(itemVO);
            }
        }
        return rootItemList;
    }

    private void genItemTree(List<ScheduleItemVO> itemVOS){
        Map<String, List<ScheduleItemVO>> itemMap = new HashMap<>();
        for(ScheduleItemVO itemVO : itemVOS){
            String key = itemVO.getCode();
            if(!key.contains(".")){
                continue;
            }

            key = key.substring(0, key.lastIndexOf("."));
            List<ScheduleItemVO> itemVOList = itemMap.get(key);
            if(itemVOList == null){
                itemVOList = new ArrayList<>();
                itemMap.put(key, itemVOList);
            }

            itemVOList.add(itemVO);
        }

        for(ScheduleItemVO itemVO : itemVOS){
            String key = itemVO.getCode();
            List<ScheduleItemVO> childItems = itemMap.get(key);
            if(childItems != null && childItems.size() > 0){
                itemVO.setChildren(childItems.toArray(new ScheduleItemVO[]{}));
            }
        }
    }

    private void setExcelRelateValue(List<ProjectPlanImportVO> planList) throws BusinessException {
        Set<String> milestoneCodeSet = new HashSet<>();
        Set<String> managerNameSet = new HashSet<>();

        for(ProjectPlanImportVO importVO : planList){
            setPlanDate(importVO);
            milestoneCodeSet.add(importVO.getMilestoneCode());
            managerNameSet.add(importVO.getManagerName());
        }

        // 查询里程碑档案
        Map<String, MilestoneVO> milestoneVOMap = milestoneQuery.queryByCodes(milestoneCodeSet.toArray(new String[0]),
                RuntimeEnvironment.getTenantId());

        for (ProjectPlanImportVO importVO : planList) {
            if (StringUtils.isNotEmpty(importVO.getMilestoneCode())){
                MilestoneVO milestoneVO = milestoneVOMap.get(importVO.getMilestoneCode());
                if (milestoneVO != null){
                    importVO.setPkMilestone(milestoneVO.getPkMilestone());
                    importVO.setMilestoneName(milestoneVO.getName());
                }
            }
        }

    }

    /**
     * 根据负责人名字，设置负责人主键
     */
    private void setPkByManagerName(ProjectPlanVO[] planVOS, String pkProject) throws BusinessException {
        TeamMemberVO[] teamMembers = teamMemberQuery.queryByProject(pkProject);
        if(teamMembers == null) return;
        String[] pkTeamMembers = new String[teamMembers.length];
        for(int i = 0; i < teamMembers.length; i++){
            if(teamMembers[i] != null){
                pkTeamMembers[i] = teamMembers[i].getPkUser();
            }
        }
        UserInfo[] userInfos = userInfoQuery.queryUsers(pkTeamMembers);
        if(userInfos == null) return;
        HashMap<String, String> recordPk = new HashMap<>();
        for(UserInfo userInfo : userInfos){
            if(recordPk.get(userInfo.getUserName()) == null){      //如果名字出现重复，取第一个
                recordPk.put(userInfo.getUserName(), userInfo.getUserId());
            }
        }
        for(ProjectPlanVO planVO : planVOS){
            if(recordPk.get(planVO.getManagerName()) != null){
                planVO.setManager(recordPk.get(planVO.getManagerName()));
            }else {
                planVO.setManagerName(null);
            }
        }
    }

    private void setPlanDate(ProjectPlanImportVO importVO) throws BusinessException {
        Calendar calendar = Calendar.getInstance();
        Date currentDate = calendar.getTime();
        Date startDate = importVO.getExpeStartDate();
        Date endDate = importVO.getExpeEndDate();
        int duration = importVO.getExpeDuration() == null || importVO.getExpeDuration() == 0 ? 1 : importVO.getExpeDuration();

        if(startDate != null && endDate != null){
            if(startDate.after(endDate)){
                throw new BusinessException(importVO.getSname() + "计划开始时间不能晚于计划结束时间");
            }
            importVO.setExpeStartDate(DateUtils.asDateBegin(DateUtils.formatDate(startDate)));
            importVO.setExpeEndDate(DateUtils.asDateEnd(DateUtils.formatDate(endDate)));
            importVO.setExpeDuration((int)DateUtils.getDaysBetween(startDate, endDate));
            return;
        }

        if(startDate == null && endDate != null){
            calendar.setTime(endDate);
            calendar.add(Calendar.DAY_OF_MONTH, -(duration - 1));
            startDate = calendar.getTime();
            importVO.setExpeStartDate(DateUtils.asDateBegin(DateUtils.formatDate(startDate)));
            importVO.setExpeEndDate(DateUtils.asDateEnd(DateUtils.formatDate(endDate)));
            return;
        }

        if(startDate != null){
            calendar.setTime(startDate);
            calendar.add(Calendar.DAY_OF_MONTH, (duration - 1));
            endDate = calendar.getTime();
            importVO.setExpeStartDate(DateUtils.asDateBegin(DateUtils.formatDate(startDate)));
            importVO.setExpeEndDate(DateUtils.asDateEnd(DateUtils.formatDate(endDate)));
            return;
        }

        startDate = currentDate;
        endDate = currentDate;
        importVO.setExpeStartDate(DateUtils.asDateBegin(DateUtils.formatDate(startDate)));
        importVO.setExpeEndDate(DateUtils.asDateEnd(DateUtils.formatDate(endDate)));
        importVO.setExpeDuration((int)DateUtils.getDaysBetween(startDate, endDate));
    }

    private void checkImportFromExcel(MultipartFile file, ScheduleVO scheduleVO) throws BusinessException{
        if(scheduleVO == null){
            throw new BusinessException("计划编制不能为空！");
        }

        if(StringUtils.isEmpty(scheduleVO.getPkProject())){
            throw new BusinessException("项目不能为空！");
        }

        if(file == null){
            throw new BusinessException("导入文件为空！");
        }

        String fileOriName = file.getOriginalFilename();
        if(StringUtils.isEmpty(fileOriName)){
            throw new BusinessException("文件信息不全！");
        }else if(!fileOriName.endsWith(".xls") && !fileOriName.endsWith(".xlsx")){
            throw new BusinessException("导入文件不是Excel格式！");
        }
    }

    /**
     * 解析Excel
     */
    private List<ProjectPlanImportVO> analyzeExcel(MultipartFile file) throws BusinessException {
        //导入Excel
        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        params.setHeadRows(1);
        params.setNeedVerfiy(true);
        ExcelImportResult<ProjectPlanImportVO> result;
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            result = ExcelImportUtil.importExcelMore(inputStream, ProjectPlanImportVO.class, params);
        } catch (Exception e) {
            log.error("计划编制导入Excel失败：" + e);
            throw new BusinessException("计划编制导入Excel失败：" + e.getMessage());
        }finally {
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("计划编制Excel导入关闭输入流失败：" + e);
                }
            }
        }

        if(result == null){
            return new ArrayList<>();
        }

        if(!result.getFailList().isEmpty()){
            StringBuilder errorInfoBuilder = new StringBuilder("如下计划项格式编写错误：[");

            for(Object object : result.getFailList()){
                ProjectPlanImportVO importVO = (ProjectPlanImportVO) object;
                errorInfoBuilder.append(importVO.getSname()).append(",");
            }

            String errorInfo = errorInfoBuilder.toString();
            errorInfo = errorInfo.substring(0, errorInfo.length() - 1) + "],请按限定格式导入。";
            throw new BusinessException(errorInfo);
        }
        return result.getList();
    }

    /**
     * 翻译关联项的值
     *
     * @param scheduleVOS 计划
     */
    private void setRelatedValue(ScheduleVO[] scheduleVOS) throws BusinessException {
        Set<String> billTypeCodeSet = new HashSet<>();
        Set<String> pkDeptSet = new HashSet<>();
        List<ScheduleItemVO> itemVOS = new ArrayList<>();
        for (ScheduleVO scheduleVO : scheduleVOS) {
            for (ScheduleItemVO itemVO : scheduleVO.getScheduleItemVOS()) {
                getRelatedItem(itemVO, billTypeCodeSet, pkDeptSet, itemVOS);
            }
        }

        Map<String, String> billTypeNameMap = billTypeInfoQueryUtils.queryNameByType(
                billTypeCodeSet.toArray(new String[]{}));
        Map<String, String> departmentNameMap = departmentInfoQueryUtils.queryNameByPks(
                pkDeptSet.toArray(new String[]{}));

        for (ScheduleVO scheduleVO : scheduleVOS) {
            for (ScheduleItemVO itemVO : scheduleVO.getScheduleItemVOS()) {
                setRelatedItemValue(itemVO, billTypeNameMap, departmentNameMap);
            }
        }

        String[] itemUserFields = new String[]{ScheduleItemVO.MANAGER, ScheduleItemVO.CREATOR,
                ScheduleItemVO.PLAN_FINISHER};
        String[] itemUserNameFields = new String[]{ScheduleItemVO.MANAGER_NAME,
                ScheduleItemVO.CREATOR_NAME,
                ScheduleItemVO.PLAN_FINISHER_NAME};
        userInfoQuery.tranUserInfoField(itemVOS.toArray(new ScheduleItemVO[]{}), itemUserFields, itemUserNameFields);

        String[] scheduleUserFields = new String[]{ScheduleVO.CREATOR};
        String[] scheduleUserNameFields = new String[]{ScheduleVO.CREATOR_NAME};
        userInfoQuery.tranUserInfoField(scheduleVOS, scheduleUserFields, scheduleUserNameFields);
    }



    /**
     * 获取需要翻译的关联项
     *
     * @param itemVO      任务节点
     * @param billTypeSet 任务关联的单据类型
     * @param pkDeptSet   任务关联的责任部门
     * @param itemVOS     所有的子级，翻译人员名称使用
     */
    private void getRelatedItem(ScheduleItemVO itemVO, Set<String> billTypeSet, Set<String> pkDeptSet, List<ScheduleItemVO> itemVOS) {
        itemVOS.add(itemVO);

        if (StringUtils.isNotEmpty(itemVO.getRelatedBillType())) {
            billTypeSet.add(itemVO.getRelatedBillType());
        }

        if (StringUtils.isNotEmpty(itemVO.getPkDepartment())) {
            pkDeptSet.add(itemVO.getPkDepartment());
        }

        if (itemVO.getChildren() != null && itemVO.getChildren().length > 0) {
            for (ScheduleItemVO childItemVO : itemVO.getChildren()) {
                getRelatedItem(childItemVO, billTypeSet, pkDeptSet, itemVOS);
            }
        }
    }

    /**
     * 对关联项进行翻译赋值
     *
     * @param itemVO            任务项
     * @param billTypeNameMap   关联单据类型描述汇总
     * @param departmentNameMap 关联部门描述汇总
     */
    private void setRelatedItemValue(ScheduleItemVO itemVO, Map<String, String> billTypeNameMap, Map<String, String> departmentNameMap) {
        if (StringUtils.isNotEmpty(itemVO.getRelatedBillType())) {
            itemVO.setRelatedBillTypeName(billTypeNameMap.get(itemVO.getRelatedBillType()));
        }
        if (StringUtils.isNotEmpty(itemVO.getPkDepartment())) {
            itemVO.setDepartmentName(departmentNameMap.get(itemVO.getPkDepartment()));
        }

        if (itemVO.getChildren() != null && itemVO.getChildren().length > 0) {
            for (ScheduleItemVO childItemVO : itemVO.getChildren()) {
                setRelatedItemValue(childItemVO, billTypeNameMap, departmentNameMap);
            }
        }
    }
}
